Sensor Fusion for Kinetis MCUs (ISSDK/KSDK version)
driver_FXAS21002.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016, NXP Semiconductor
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * o Redistributions of source code must retain the above copyright notice, this list
9  * of conditions and the following disclaimer.
10  *
11  * o Redistributions in binary form must reproduce the above copyright notice, this
12  * list of conditions and the following disclaimer in the documentation and/or
13  * other materials provided with the distribution.
14  *
15  * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from this
17  * software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 /*! \file driver_FXAS21002.c
31  \brief Provides init() and read() functions for the FXAS21002 gyroscope
32 */
33 
34 #include "board.h" // generated by Kinetis Expert. Long term - merge sensor_board.h into this file
35 #include "sensor_fusion.h" // Sensor fusion structures and types
36 #include "sensor_drv.h"
37 #include "sensor_io_i2c.h" // Low level IS-SDK prototype driver
38 #include "drivers.h" // Device specific drivers supplied by NXP (can be replaced with user drivers)
39 #include "fxas21002.h"
40 
41 // Includes support for pre-production FXAS21000 registers and constants which are not supported via IS-SDK
42 #define FXAS21000_STATUS 0x00
43 #define FXAS21000_F_STATUS 0x08
44 #define FXAS21000_F_SETUP 0x09
45 #define FXAS21000_WHO_AM_I 0x0C
46 #define FXAS21000_CTRL_REG0 0x0D
47 #define FXAS21000_CTRL_REG1 0x13
48 #define FXAS21000_CTRL_REG2 0x14
49 #define FXAS21000_WHO_AM_I_VALUE 0xD1 // engineering and production
50 #define FXAS21000_COUNTSPERDEGPERSEC 20 // 1600dps range
51 #define FXAS21002_COUNTSPERDEGPERSEC 16 // for 2000dps=32000 counts
52 
53 #define FXAS21002_GYRO_FIFO_SIZE 32 ///< FXAX21000, FXAS21002 have 32 element FIFO
54 
55 #if F_USING_GYRO
56 
57 // Command definition to read the WHO_AM_I value.
58 const registerreadlist_t FXAS21002_WHO_AM_I_READ[] =
59 {
60  { .readFrom = FXAS21002_WHO_AM_I, .numBytes = 1 }, __END_READ_DATA__
61 };
62 
63 // Command definition to read the number of entries in the gyro status register.
64 const registerreadlist_t FXAS21002_F_STATUS_READ[] =
65 {
66  { .readFrom = FXAS21002_STATUS, .numBytes = 1 }, __END_READ_DATA__
67 };
68 
69 // Command definition to read the number of entries in the accel FIFO.
70 registerreadlist_t FXAS21002_DATA_READ[] =
71 {
72  { .readFrom = FXAS21002_OUT_X_MSB, .numBytes = 1 }, __END_READ_DATA__
73 };
74 
75 // Each entry in a RegisterWriteList is composed of: register address, value to write, bit-mask to apply to write (0 enables)
76 const registerwritelist_t FXAS21000_Initialization[] =
77 {
78  // write 0000 0000 = 0x00 to CTRL_REG1 to place FXOS21000 in Standby
79  // [7]: ZR_cond=0
80  // [6]: RST=0
81  // [5]: ST=0 self test disabled
82  // [4-2]: DR[2-0]=000 for 200Hz ODR
83  // [1]: Active=0 for Standby mode
84  // [0]: Ready=0 but irrelevant since Active bit over-rides
85  { FXAS21000_CTRL_REG1, 0x00, 0x00 }, // write 0100 0000 = 0x40 to F_SETUP to enable FIFO in continuous mode
86 
87  // [7-6]: F_MODE[1-0]=01 for FIFO continuous mode
88  // [5-0]: F_WMRK[5-0]=000000 for no FIFO watermark
89  { FXAS21000_F_SETUP, 0x40, 0x00 },
90 
91  // write 0000 0000 = 0x00 to CTRL_REG0 to configure range
92  // [7-6]: unused=00
93  // [5]: SPIW=0 4 wire SPI (irrelevant)
94  // [4-3]: SEL[1-0]=00 for HPF cutoff but disabled in HPF_EN
95  // [2]: HPF_EN=0 disable HPF
96  // [1-0]: FS[1-0]=00 for 1600dps
97  { FXAS21000_CTRL_REG0, 0x00, 0x00 },
98 
99  // write 000X XX10 to CTRL_REG1 to configure ODR and enter Active mode
100  // [7]: Reserved=0
101  // [6]: RST=0 for no reset
102  // [5]: ST=0 self test disabled
103  // [4-2]: DR[2-0]=111 also for 12.5Hz ODR giving 0x1E
104  // [4-2]: DR[2-0]=110 for 12.5Hz ODR giving 0x1A
105  // [4-2]: DR[2-0]=101 for 25Hz ODR giving 0x16
106  // [4-2]: DR[2-0]=100 for 50Hz ODR giving 0x12
107  // [4-2]: DR[2-0]=011 for 100Hz ODR giving 0x0E
108  // [4-2]: DR[2-0]=010 for 200Hz ODR giving 0x0A
109  // [4-2]: DR[2-0]=001 for 400Hz ODR giving 0x06
110  // [4-2]: DR[2-0]=000 for 800Hz ODR giving 0x02
111  // [1]: Active=1 for Active mode
112  // [0]: Ready=0 but irrelevant since Active bit over-rides
113 #if (GYRO_ODR_HZ <= 1) // select 1.5625Hz ODR
114  { FXAS21000_CTRL_REG1, 0x1E, 0x00 },
115 #elif (GYRO_ODR_HZ <= 3) // select 3.125Hz ODR
116  { FXAS21000_CTRL_REG1, 0x1A, 0x00 },
117 #elif (GYRO_ODR_HZ <= 6) // select 6.25Hz ODR
118  { FXAS21000_CTRL_REG1, 0x16, 0x00 },
119 #elif (GYRO_ODR_HZ <= 12) // select 12.5Hz ODR
120  { FXAS21000_CTRL_REG1, 0x12, 0x00 },
121 #elif (GYRO_ODR_HZ <= 25) // select 25.0Hz ODR
122  { FXAS21000_CTRL_REG1, 0x0E, 0x00 },
123 #elif (GYRO_ODR_HZ <= 50) // select 50.0Hz ODR
124  { FXAS21000_CTRL_REG1, 0x0A, 0x00 },
125 #elif (GYRO_ODR_HZ <= 100) // select 100.0Hz ODR
126  { FXAS21000_CTRL_REG1, 0x06, 0x00 },
127 #else // select 200Hz ODR
128  { FXAS21000_CTRL_REG1, 0x02, 0x00 },
129 #endif
130  __END_WRITE_DATA__
131 };
132 
133 // Each entry in a RegisterWriteList is composed of: register address, value to write, bit-mask to apply to write (0 enables)
134 const registerwritelist_t FXAS21002_Initialization[] =
135 {
136  // write 0000 0000 = 0x00 to CTRL_REG1 to place FXOS21000 in Standby
137  // [7]: ZR_cond=0
138  // [6]: RST=0
139  // [5]: ST=0 self test disabled
140  // [4-2]: DR[2-0]=000 for 200Hz ODR
141  // [1]: Active=0 for Standby mode
142  // [0]: Ready=0 but irrelevant since Active bit over-rides
143  { FXAS21002_CTRL_REG1, 0x00, 0x00 },
144 
145  // [7-6]: F_MODE[1-0]=01 for FIFO continuous mode
146  // [5-0]: F_WMRK[5-0]=000000 for no FIFO watermark
147  { FXAS21002_F_SETUP, 0x40, 0x00 },
148 
149  // write 0000 0000 = 0x00 to CTRL_REG0 to configure range and LPF
150  // [7-6]: BW[1-0]=00 for least aggressive LPF (0.32 * ODR cutoff for all ODR ie 64Hz cutoff at 200Hz ODR)
151  // [5]: SPIW=0 4 wire SPI (irrelevant)
152  // [4-3]: SEL[1-0]=00 for HPF cutoff but disabled in HPF_EN
153  // [2]: HPF_EN=0 to disable HPF
154  // [1-0]: FS[1-0]=00 for 2000dps
155  { FXAS21002_CTRL_REG0, 0x00, 0x00 },
156 
157  // write 0000 1000 = 0x08 to CTRL_REG3 to set FIFO address wraparound on read
158  // [7-4]: Reserved=0000
159  // [3]: WRAPTOONE=1 to permit burst FIFO read with address wrapround to OUT_X_MSB
160  // [2]: EXTCTRLEN=0 for default INT2 configuration as output
161  // [1]: Reserved=0
162  // [0]: FS_DOUBLE=0 for normal 2000dps range
163  { FXAS21002_CTRL_REG3, 0x08, 0x00 },
164 
165  // write 000X XX10 to CTRL_REG1 to configure ODR and enter Active mode
166  // [7]: Reserved=0
167  // [6]: RST=0 for no reset
168  // [5]: ST=0 self test disabled
169  // [4-2]: DR[2-0]=111 also for 12.5Hz ODR giving 0x1E
170  // [4-2]: DR[2-0]=110 for 12.5Hz ODR giving 0x1A
171  // [4-2]: DR[2-0]=101 for 25Hz ODR giving 0x16
172  // [4-2]: DR[2-0]=100 for 50Hz ODR giving 0x12
173  // [4-2]: DR[2-0]=011 for 100Hz ODR giving 0x0E
174  // [4-2]: DR[2-0]=010 for 200Hz ODR giving 0x0A
175  // [4-2]: DR[2-0]=001 for 400Hz ODR giving 0x06
176  // [4-2]: DR[2-0]=000 for 800Hz ODR giving 0x02
177  // [1]: Active=1 for Active mode
178  // [0]: Ready=0 but irrelevant since Active bit over-rides
179  // These values are different than the FXAS21000 values
180 #if (GYRO_ODR_HZ <= 12) // select 12.5Hz ODR
181  { FXAS21002_CTRL_REG1, 0x1A, 0x00 },
182 #elif (GYRO_ODR_HZ <= 25) // select 25Hz ODR
183  { FXAS21002_CTRL_REG1, 0x16, 0x00 },
184 #elif (GYRO_ODR_HZ <= 50) // select 50Hz ODR
185  { FXAS21002_CTRL_REG1, 0x12, 0x00 },
186 #elif (GYRO_ODR_HZ <= 100) // select 100Hz ODR
187  { FXAS21002_CTRL_REG1, 0x0E, 0x00 },
188 #elif (GYRO_ODR_HZ <= 200) // select 200Hz ODR
189  { FXAS21002_CTRL_REG1, 0x0A, 0x00 },
190 #elif (GYRO_ODR_HZ <= 400) // select 400Hz ODR
191  { FXAS21002_CTRL_REG1, 0x06, 0x00 },
192 #else // select 800Hz ODR
193  { FXAS21002_CTRL_REG1, 0x02, 0x00 },
194 #endif
195  __END_WRITE_DATA__
196 };
197 
198 // All sensor drivers and initialization functions have the same prototype
199 // sensor = pointer to linked list element used by the sensor fusion subsystem to specify required sensors
200 
201 // sfg = pointer to top level (generally global) data structure for sensor fusion
203 {
204 
205  int32_t status;
206  uint8_t reg;
207  status = Register_I2C_Read(sensor->bus_driver, sensor->addr, FXAS21002_WHO_AM_I, 1, &reg);
208  if (status==SENSOR_ERROR_NONE) {
209  sfg->Gyro.iWhoAmI = reg;
210  switch (reg) {
211  case FXAS21002_WHO_AM_I_WHOAMI_PROD_VALUE:
212  case FXAS21002_WHO_AM_I_WHOAMI_PRE_VALUE:
213  case FXAS21002_WHO_AM_I_WHOAMI_OLD_VALUE: break;
214  default:
215  // whoAmI will retain default value of zero
216  return SENSOR_ERROR_INIT; // return with error
217  }
218  } else {
219  return status; // return with error
220  }
221 
222  // configure FXAS21000 or FXAS21002 depending on WHOAMI value read
223  switch (sfg->Gyro.iWhoAmI) {
225  // Configure and start the FXAS21000 sensor. This does multiple register writes
226  // (see FXAS21009_Initialization definition above)
227  status = Sensor_I2C_Write(sensor->bus_driver, sensor->addr, FXAS21000_Initialization );
228  sfg->Gyro.iCountsPerDegPerSec = FXAS21000_COUNTSPERDEGPERSEC;
229  sfg->Gyro.fDegPerSecPerCount = 1.0F / FXAS21000_COUNTSPERDEGPERSEC;
230  break;
231  case (FXAS21002_WHO_AM_I_WHOAMI_PRE_VALUE):
232  case (FXAS21002_WHO_AM_I_WHOAMI_PROD_VALUE):
233  status = Sensor_I2C_Write(sensor->bus_driver, sensor->addr, FXAS21002_Initialization );
234  sfg->Gyro.iCountsPerDegPerSec = FXAS21002_COUNTSPERDEGPERSEC;
235  sfg->Gyro.fDegPerSecPerCount = 1.0F / FXAS21002_COUNTSPERDEGPERSEC;
236  break;
237  }
238  sfg->Gyro.iFIFOCount=0;
239  sensor->isInitialized = F_USING_GYRO;
240  sfg->Gyro.isEnabled = true;
241  return (status);
242 }
243 
244 // read FXAS21002 gyro over I2C
246 {
247  uint8_t I2C_Buffer[6 * FXAS21002_GYRO_FIFO_SIZE]; // I2C read buffer
248  int8_t j; // scratch
249  uint8_t sensor_fifo_count = 1;
250  int32_t status;
251  int16_t sample[3];
252 
253  if(sensor->isInitialized != F_USING_GYRO)
254  {
255  return SENSOR_ERROR_INIT;
256  }
257 
258  // read the F_STATUS register (mapped to STATUS) and extract number of measurements available (lower 6 bits)
259  status = Sensor_I2C_Read(sensor->bus_driver, sensor->addr, FXAS21002_F_STATUS_READ, I2C_Buffer );
260  if (status==SENSOR_ERROR_NONE) {
261  sensor_fifo_count = I2C_Buffer[0] & FXAS21002_F_STATUS_F_CNT_MASK ;
262  // return if there are no measurements in the FIFO.
263  // this will only occur when the FAST_LOOP_HZ equals or exceeds GYRO_ODR_HZ
264  if (sensor_fifo_count == 0) return(SENSOR_ERROR_READ);
265  } else {
266  return(status);
267  }
268 
269  // at this point there must be at least one measurement in the FIFO available to read.
270  // handle the FXAS21000 and FXAS21002 differently because only FXAS21002 supports WRAPTOONE feature.
271  if (sfg->Gyro.iWhoAmI == FXAS21002_WHO_AM_I_WHOAMI_OLD_VALUE)
272  {
273  // read six sequential gyro output bytes
274  FXAS21002_DATA_READ[0].readFrom = FXAS21002_OUT_X_MSB;
275  FXAS21002_DATA_READ[0].numBytes = 6;
276 
277  // for FXAS21000, perform sequential 6 byte reads
278  for (j = 0; j < sensor_fifo_count; j++)
279  {
280  // read one set of measurements totalling 6 bytes
281  status = Sensor_I2C_Read(sensor->bus_driver, sensor->addr, FXAS21002_DATA_READ, I2C_Buffer );
282 
283  if (status==SENSOR_ERROR_NONE) {
284  // place the measurements read into the gyroscope buffer structure
285  sample[CHX] = (I2C_Buffer[0] << 8) | I2C_Buffer[1];
286  sample[CHY] = (I2C_Buffer[2] << 8) | I2C_Buffer[3];
287  sample[CHZ] = (I2C_Buffer[4] << 8) | I2C_Buffer[5];
288  conditionSample(sample); // truncate negative values to -32767
289  addToFifo((FifoSensor*) &(sfg->Gyro), GYRO_FIFO_SIZE, sample);
290  }
291  }
292  } // end of FXAS21000 FIFO read
293  else
294  {
295  // for FXAS21002, clear the FIFO in one using WRAPTOONE feature
296  FXAS21002_DATA_READ[0].readFrom = FXAS21002_OUT_X_MSB;
297  FXAS21002_DATA_READ[0].numBytes = 6 * sensor_fifo_count;
298  status = Sensor_I2C_Read(sensor->bus_driver, sensor->addr, FXAS21002_DATA_READ, I2C_Buffer );
299 
300  if (status==SENSOR_ERROR_NONE) {
301  for (j = 0; j < sensor_fifo_count; j++) {
302  // place the measurements read into the gyroscope buffer structure
303  sample[CHX] = (I2C_Buffer[6*j + 0] << 8) | I2C_Buffer[6*j + 1];
304  sample[CHY] = (I2C_Buffer[6*j + 2] << 8) | I2C_Buffer[6*j + 3];
305  sample[CHZ] = (I2C_Buffer[6*j + 4] << 8) | I2C_Buffer[6*j + 5];
306  conditionSample(sample); // truncate negative values to -32767
307  addToFifo((FifoSensor*) &(sfg->Gyro), GYRO_FIFO_SIZE, sample);
308  }
309  }
310  } // end of optimized FXAS21002 FIFO read
311 
312  return status;
313 }
314 
315 
316 // Each entry in a RegisterWriteList is composed of: register address, value to write, bit-mask to apply to write (0 enables)
317 const registerwritelist_t FXAS21002_IDLE[] =
318 {
319  // Reset to Standby
320  { FXAS21000_CTRL_REG1, 0x00, 0x00 },
321  __END_WRITE_DATA__
322 };
323 
324 // FXAS21002_Idle places the gyro into READY mode (wakeup time = 1/ODR+5ms)
326 {
327  int32_t status;
328  if(sensor->isInitialized == F_USING_GYRO) {
329  status = Sensor_I2C_Write(sensor->bus_driver, sensor->addr, FXAS21002_IDLE );
330  sensor->isInitialized = 0;
331  sfg->Gyro.isEnabled = false;
332  } else {
333  return SENSOR_ERROR_INIT;
334  }
335  return status;
336 }
337 #endif
#define F_USING_GYRO
nominally 0x0004 if a gyro is to be used, 0x0000 otherwise
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
#define FXAS21000_CTRL_REG1
void addToFifo(FifoSensor *sensor, uint16_t maxFifoSize, int16_t sample[3])
addToFifo is called from within sensor driver read functions
The top level fusion structure.
void * bus_driver
should be of type (ARM_DRIVER_I2C* for I2C-based sensors, ARM_DRIVER_SPI* for SPI) ...
#define GYRO_FIFO_SIZE
FXAX21000, FXAS21002 have 32 element FIFO.
The FifoSensor union allows us to use common pointers for Accel, Mag & Gyro logical sensor structures...
#define FXAS21002_GYRO_FIFO_SIZE
FXAX21000, FXAS21002 have 32 element FIFO.
int8_t FXAS21002_Read(PhysicalSensor *sensor, SensorFusionGlobals *sfg)
#define FXAS21000_CTRL_REG0
The sensor_fusion.h file implements the top level programming interface.
#define CHZ
Provides function prototypes for driver level interfaces.
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
void conditionSample(int16_t sample[3])
conditionSample ensures that we never encounter the maximum negative two&#39;s complement value for a 16-...
int8_t FXAS21002_Idle(PhysicalSensor *sensor, SensorFusionGlobals *sfg)
An instance of PhysicalSensor structure type should be allocated for each physical sensors (combo dev...
#define FXAS21000_COUNTSPERDEGPERSEC
uint16_t isInitialized
Bitfields to indicate sensor is active (use SensorBitFields from build.h)
#define FXAS21000_WHO_AM_I_VALUE
#define FXAS21002_COUNTSPERDEGPERSEC
SensorFusionGlobals sfg
This is the primary sensor fusion data structure.
#define FXAS21000_F_SETUP
int8_t FXAS21002_Init(PhysicalSensor *sensor, SensorFusionGlobals *sfg)
uint16_t addr
I2C address if applicable.